#include "FileReader.h"
#include <stdlib.h>
#include <exception>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using std::cerr;

EncoderSettings FileReader::readEncoderSettings(string filename)
{
    ifstream file;

	file.open(filename);
    EncoderSettings config;

    if (!file.good()) {
        cerr << "No config file specified.\n";
        exit(1);
    }

    while (!file.eof()) {
		string line;
		std::getline(file, line);

        try
        {
            addEncoderSetting(config, line);
        }
        catch (std::exception)
        {
            cerr << "Wrong config file format.\n";
            exit(3);
        }
    }

    return config;
}

DecoderSettings FileReader::readDecoderSettings(string filename)
{
    ifstream file;

	file.open(filename);

    DecoderSettings config;

    if (!file.good()) {
        cerr << "No config file specified.\n";
        exit(1);
    }

    while (!file.eof()) {
        string line;
		std::getline(file, line);

        try
        {
            addDecoderSetting(config, line);
        }
        catch (std::exception)
        {
            cerr << "Wrong config file format.\n";
            exit(3);
        }
    }

    return config;
}

QuantizationMatrix* FileReader::readMatrix(string filename)
{
    ifstream file;
    QuantizationMatrix* matrix = new QuantizationMatrix(4);
    int m[16];
    int position=0;

	file.open(filename);

    if (!file.good()) {
        cerr << "No matrix file specified.\n";
        exit(4);
    }

    while (!file.eof()) {
        string line;

		std::getline(file, line);

        try
        {
            addMatrixRow(line, m, position);
        }
        catch (std::exception)
        {
            cerr << "Wrong matrix file format.\n";
            exit(6);
        }
    }

    matrix->setMatrixRowMajor( m);

    return matrix;
}

void FileReader::openFile(string filename)
{
    _file.open(filename, fstream::in | ios::binary);
}

Frame *FileReader::readCompressedData(bool &status)
{
    if(_file.eof())
        return NULL;

    int size = 4;
    uint8_t *buff = new uint8_t[size];
    Frame *data;

    if((status = !_file.fail()))
    {
        _file.read((char*)buff, size);

        util::BitStreamReader bsr(buff, size);
        int type = (int) bsr.get_bit();
        int length = bsr.get(31);

        delete buff;
        buff = new uint8_t[length];

        _file.read((char*)buff, length);

        data = new Frame(type, length, buff);
    }

    return data;
}

Frame *FileReader::readUncompressedData(int frameSize, bool &status)
{
    if(_file.peek() == EOF)
        return NULL;

    uint8_t *buff = new uint8_t[frameSize];
    Frame *data;

    if((status = !_file.fail()))
    {
        _file.read((char*)buff, frameSize);

        data = new Frame(2, frameSize, buff);
    }

    _file.ignore(frameSize/2);

    return data;
}

void FileReader::closeFile()
{
    _file.close();
}

void FileReader::addEncoderSetting(EncoderSettings &config, string &line) throw()
{
    if (!line.empty()) {
        if( line.find("rawfile=") == 0 ){
			string parameter = "rawfile=";
			line.erase(line.find(parameter), parameter.length());
            config.setRawfile(line);
        } else if( line.find("encfile=") == 0){
            string parameter = "encfile=";
			line.erase(line.find(parameter), parameter.length());
            config.setEncfile(line);
        } else if( line.find("quantfile=") == 0){
            string parameter = "quantfile=";
			line.erase(line.find(parameter), parameter.length());
            config.setQuantfile(line);
        } else if( line.find("logfile=") == 0){
            string parameter = "logfile=";
			line.erase(line.find(parameter), parameter.length());
            config.setLogfile(line);
        } else if( line.find("width=") == 0){
            string parameter = "width=";
			line.erase(line.find(parameter), parameter.length());
            config.setWidth(atoi(line.c_str()));
        } else if( line.find("height=") == 0){
            string parameter = "height=";
			line.erase(line.find(parameter), parameter.length());
            config.setHeight(atoi(line.c_str()));
        } else if( line.find("rle=") == 0){
            string parameter = "rle=";
			line.erase(line.find(parameter), parameter.length());
            config.setRLE(atoi(line.c_str()));
        } else if( line.find("gop=") == 0){
            string parameter = "gop=";
			line.erase(line.find(parameter), parameter.length());
            config.setGOP(atoi(line.c_str()));
        } else if( line.find("merange=") == 0){
            string parameter = "merange=";
			line.erase(line.find(parameter), parameter.length());
            config.setMerange(atoi(line.c_str()));
        }
    }
}

void FileReader::addDecoderSetting(DecoderSettings &config, string &line) throw()
{
    if (!line.empty()) {
        if( line.find("decfile=") == 0){
			string parameter = "decfile=";
			line.erase(line.find(parameter), parameter.length());
            config.setDecfile(line);
        } else if( line.find("encfile=") == 0){
			string parameter = "encfile=";
			line.erase(line.find(parameter), parameter.length());
            config.setEncfile(line);
        } else if( line.find("logfile=") == 0){
            string parameter = "logfile=";
			line.erase(line.find(parameter), parameter.length());
            config.setLogfile(line);
        } else if( line.find("motioncompensation=") == 0){
            string parameter = "motioncompensation=";
			line.erase(line.find(parameter), parameter.length());
            config.setMotionCompensation(atoi(line.c_str()));
        }
    }
}

void FileReader::addMatrixRow(string &line, int *m, int &position) throw()
{
    if (!line.empty()) {
		istringstream iss(line);
		vector<string> list;

		do
		{
			string sub;
			iss >> sub;
			if(!sub.empty())
				list.push_back(sub);
		}while(iss);

        if (list.size() != 4)
            throw;

        vector<string>::const_iterator constIterator;
		for (constIterator = list.begin(); constIterator != list.end(); ++constIterator)
			m[position++] = atoi((*constIterator).c_str());
    }
}

int FileReader::getFileSize()
{
	int currentPos = _file.tellg();

	_file.seekg(0, std::ios::end);

	int length = _file.tellg();

	_file.seekg(currentPos);

	return length;
}
